feat(shopping): add Order Management API commands - #253
Conversation
Add Shopping catalog, checkout, and order commands backed by the direct Order Management Katana service. - Add configurable Shopping service URL resolution. - Request the full Shopping OAuth scope bundle in one consent flow. - Add catalog search/lookup/get and checkout create/get/update/complete. - Require idempotency keys for completion and avoid automatic replays. - Add bounded order-read polling for eventual consistency. - Document the completed-checkout read limitation and direct-service setup. - Add client, resolver, scope, command discovery, and dry-run coverage. Pending: - Register shopping.catalog:read, shopping.checkout:execute, and shopping.order:read for the CLI OAuth client. - Run authenticated Test-tier catalog and checkout checks. - Authorize and execute a real Test-tier completion smoke only when needed. - Switch to front-door routing/PAT exchange when available. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
The new Shopping HTTP client currently emits transport debug logs that can capture sensitive customer/order payloads, and the top-level help text is slightly misleading about supported env-var overrides.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR introduces a new gddy shopping module that talks directly to the Order Management Shopping API (Katana endpoint) so agents/users can browse the catalog and run checkout → order flows from the CLI while Shopping is not yet front-doored.
Changes:
- Added the
shoppingcommand group with catalog, checkout, and order read commands plus guide/help metadata. - Implemented a dedicated Shopping HTTP client and shared helpers (JSON body/file parsing, idempotency-key validation, bounded polling for eventual consistency).
- Added Shopping API base-URL resolution via
<ENV>_SHOPPING_URL,SHOPPING_URL, andshopping_urlin the environments TOML, plus registered new OAuth scopes.
File summaries
| File | Description |
|---|---|
| rust/src/shopping/order/mod.rs | Adds the shopping order command group wiring. |
| rust/src/shopping/order/get.rs | Implements shopping order get with optional bounded polling. |
| rust/src/shopping/mod.rs | Registers the Shopping module, scopes bundle, and top-level help text. |
| rust/src/shopping/guides/shopping.md | Documents configuration, auth scopes, and recommended workflow. |
| rust/src/shopping/common.rs | Shared helpers for client creation, JSON input, idempotency, and polling. |
| rust/src/shopping/client.rs | New reqwest-based Shopping API client and error mapping. |
| rust/src/shopping/checkout/update.rs | Implements full-replacement checkout update with --body/--file and dry-run. |
| rust/src/shopping/checkout/mod.rs | Adds the shopping checkout command group wiring. |
| rust/src/shopping/checkout/get.rs | Implements shopping checkout get (with guidance not to use post-completion). |
| rust/src/shopping/checkout/create.rs | Implements shopping checkout create with raw JSON input and dry-run. |
| rust/src/shopping/checkout/complete.rs | Implements shopping checkout complete (idempotency required, optional wait-for-order). |
| rust/src/shopping/catalog/search.rs | Implements shopping catalog search with JSON input. |
| rust/src/shopping/catalog/mod.rs | Adds the shopping catalog command group wiring. |
| rust/src/shopping/catalog/lookup.rs | Implements shopping catalog lookup with JSON input. |
| rust/src/shopping/catalog/get.rs | Implements shopping catalog get (product details) with JSON input. |
| rust/src/scopes.rs | Registers Shopping OAuth scopes in the global scope registry. |
| rust/src/main.rs | Wires the Shopping module into the CLI module list. |
| rust/src/environments/shopping.rs | Adds Shopping base-URL resolver with env var precedence + tests. |
| rust/src/environments/mod.rs | Exposes shopping_url resolver from environments module. |
| rust/src/environments/config.rs | Adds shopping_url to environment TOML config struct and defaults. |
Review details
Suppressed comments (1)
rust/src/shopping/client.rs:98
--debug transportlogging of raw response bytes can leak customer/order details (and potentially payment-related fields) when interacting with Shopping. If transport logging is needed, prefer logging only status/headers or implementing explicit redaction for sensitive JSON fields.
let bytes = response.bytes().await?;
cli_engine::transport::debug_log_reqwest_response(status, &headers, &bytes);
- Files reviewed: 20/20 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…d per returned product, including more sensible next steps
Co-Authored-By: Claude <noreply@anthropic.com>
Clarify customer-facing Shopping API terminology, checkout request guidance, completion safety, and order retrieval behavior. Remove endpoint-override setup from the Shopping guide while retaining its actionable runtime configuration error. Co-Authored-By: Claude <noreply@anthropic.com>
…rt... and a few other tweaks
Add catalog currency selection and currency-aware display, preserve full API data for JSON output, and streamline checkout creation through completion. Keep completion single-shot with generated idempotency keys and move order visibility polling to order retrieval. Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Dry-run metadata, retry error handling, generated commands, URL construction, and advertised behavior have unresolved correctness issues.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (2)
rust/src/shopping/checkout/complete.rs:117
- This command does not expose the
--wait-for-orderoption advertised in the PR description, and the handler never callswait_for_orderafter completion. Either implement the bounded completion polling flow or update the PR description so users do not expect this flag.
"Places a real order. Use --payment-instrument for one saved payment instrument, \
or --body/--file for advanced payment or billing-address fields. Use --idempotency-key \
to control retries, or omit it to let gddy generate and return one. The CLI never retries \
completion automatically. Read the resulting order with `shopping order get <order-id> --wait`.",
rust/src/shopping/catalog/search.rs:412
- Values such as
--queryand--cursorare user/API-controlled and are interpolated inside single quotes without escaping. A query likeO'Reillyproduces an invalid next-page command; use structured next-action parameters or a cross-shell-safe quoting helper.
fn append_search_flag(command: &mut String, name: &str, value: Option<&Value>) {
if let Some(value) = value.and_then(Value::as_str) {
command.push_str(&format!(" --{name} '{value}'"));
}
- Files reviewed: 18/18 changed files
- Comments generated: 8
- Review effort level: Balanced
- Render safe cross-platform structured next actions in human output\n- Mark checkout dry runs and preserve non-404 order-read failures\n- Encode dynamic checkout/order path segments\n- Show concise catalog lookup and bounded payment method choices\n- Render final totals only when response currency is available\n- Document the updated checkout experience Co-Authored-By: Claude <noreply@anthropic.com>
Add httpmock coverage for catalog, checkout, and order routes, request metadata, encoded identifiers, empty successes, and HTTP error handling. Also move two existing test modules to the ends of their files to satisfy Clippy's items-after-test-module lint. Co-Authored-By: Claude <noreply@anthropic.com>
| .with_long( | ||
| "Browse GoDaddy products, create/update/complete checkout, and view completed orders.\n\ | ||
| \n\ | ||
| Shopping commands request the required OAuth permissions together so you can \ |
There was a problem hiding this comment.
What does this mean? That it requests all permissions no matter what you do? I am not sure users would understand this text.
There was a problem hiding this comment.
Makes sense... Probably unnecessary.
There was a problem hiding this comment.
Removed the customer-facing permission and scope explanation; required scopes remain internal command metadata.
| # Shopping API | ||
|
|
||
| `gddy shopping` integrates with the Shopping API. |
There was a problem hiding this comment.
The CLI is an abstraction over APIs; we should be focused on telling customers what they can do, not which APIs are being called.
There was a problem hiding this comment.
| # Shopping API | |
| `gddy shopping` integrates with the Shopping API. | |
| # Shopping for GoDaddy Products | |
| Use `gddy shopping` commands to purchase GoDaddy's products and review your past purchases. |
There was a problem hiding this comment.
will update
There was a problem hiding this comment.
Reworked the guide around customer outcomes: discover products, manage a cart, place an order, and review purchases.
| ## Authentication | ||
|
|
||
| Every Shopping command requests these OAuth scopes together, so the first command | ||
| can take the customer through one consent flow for the complete lifecycle: | ||
|
|
||
| ```text | ||
| shopping.catalog:read | ||
| shopping.checkout:execute | ||
| shopping.order:read | ||
| ``` | ||
|
|
||
| You can authenticate before running a workflow: | ||
|
|
||
| ```bash | ||
| gddy auth login \ | ||
| --scope shopping.catalog:read \ | ||
| --scope shopping.checkout:execute \ | ||
| --scope shopping.order:read | ||
| ``` | ||
|
|
||
| Shopping requests use the selected environment's standard API front door. OAuth requests the | ||
| complete lifecycle scope bundle above in one consent flow. PAT support requires those Shopping | ||
| scopes to be available on the Developer Portal and is tracked separately. |
There was a problem hiding this comment.
Is any of this something a user needs to know? Users aren't going to have any environments besides prod and in edge cases OTE. They're not going to know what "front door" means. This "is tracked separately" doesn't make sense for users either...
I think this entire guide needs a rewrite so it is geared toward users of the CLI. My suggested outline:
- Introduction, what this guide teaches you (how to buy GoDaddy products)
- Concepts (what's in a catalog, the cart, payment methods, etc. I am writing this before reviewing the whole thing, so whatever concepts the CLI exposes, not the ones I'm speculating on)
- How to accomplish specific tasks (command sequence, explain anything non-obvious)
There was a problem hiding this comment.
SOunds good. Will take another stab at it.
There was a problem hiding this comment.
Rewrote the guide as a customer-focused catalog-to-cart-to-order journey and removed internal environment/front-door material.
|
|
||
| const PAYMENT_INSTRUMENT_LIMIT: usize = 5; | ||
|
|
||
| fn available_payment_instruments(checkout: &Value, show_all: bool) -> Vec<Value> { |
There was a problem hiding this comment.
We should have a separate command for listing payment instruments.
There was a problem hiding this comment.
I agree, but it's a bit complicated.. Applicable payment methods are really specific to the checkout context. For instance, if the currency were to change, it could potentially change the available payment options - this is how FOS works as well (and perhaps why UCP doesn't have a separate way to get available payments).
If anything, let's defer explicit commands for this for first release. I will try to make the guide better to help users understand the flow easily.
There was a problem hiding this comment.
If we want, I can expose a command that lists available payments in a checkout session.
There was a problem hiding this comment.
Deferred a standalone payment-method command for this release: eligible methods are cart-specific. Cart create/get exposes the contextual choices and IDs.
| saved instrument for selection at completion. | ||
|
|
||
| A stored payment instrument normally supplies its saved billing address automatically. Use a | ||
| JSON document when you need an address override or other advanced nested fields: |
There was a problem hiding this comment.
I'm not sure a sample JSON document makes sense. If JSON is being used, that would be something an AI agent would probably need to do for the human, and the AI agent should have a schema so it knows the shape of the JSON. Same for all these other advanced options.
I'd suggest either omitting these JSON/file parameters or at least having the guide link agents to where they can get the JSON schema.
There was a problem hiding this comment.
ok, maybe just stick to simple inputs all the way through then... at least for now... will address
There was a problem hiding this comment.
Removed raw JSON walkthroughs from the guide; the main journey now uses only simple command inputs. Advanced inputs remain available for exceptional use.
There was a problem hiding this comment.
Update: the later checkout-flow refinement removed the remaining raw --body/--file inputs from Shopping commands. The only JSON input retained is the constrained --billing-address option on completion; the normal flow uses command flags.
| @@ -0,0 +1,107 @@ | |||
| use serde_json::Value; | |||
|
|
|||
| /// Shopping amounts are ISO-4217 minor units. Their decimal scale derives from the returned | |||
There was a problem hiding this comment.
Make sure we're not duplicating the currency formatting we already have for domains. If it's the same standard, we're using a library that understands the standard.
There was a problem hiding this comment.
Will address
There was a problem hiding this comment.
Consolidated ISO-4217 minor-unit formatting on the existing Domains implementation; Shopping retains only its response-shape extraction.
| /// Mirrors cli-engine placeholder substitution for custom human views. The | ||
| /// structured template and parameters remain in the output envelope. |
There was a problem hiding this comment.
Claude... why do you keep "mirroring" functionality (duplicating) instead of reusing what we already have? We already have a standard output envelope to include these actions in a standard way. If we really need to duplicate code, we need a better explanation on why that is necessary.
There was a problem hiding this comment.
Agreed! will have it take a closer look.
There was a problem hiding this comment.
Removed project-local next-action display/substitution logic. cli-engine now renders standard structured next-action footers for custom views.
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Use customer-focused purchase-option and checkout-session inputs, richer shared human output, scoped billing addresses, and the checkout's selected payment method for completion. Co-Authored-By: Claude <noreply@anthropic.com>
Add API-derived category discovery with a six-hour, per-environment cache and an explicit refresh option. Surface categories in human output and the Shopping guide, and remove the stale static category validator so live catalog values remain supported.\n\nMark the complete Shopping command tree as Beta through the existing feature-flag mechanism and cover its visibility at GA and Beta stages.\n\nCo-Authored-By: Claude <noreply@anthropic.com>
Update rustls to 0.23.45 and rustls-webpki to 0.103.15 to address RUSTSEC-2026-0285, a TLS 1.3 handshake validation issue.\n\nCo-Authored-By: Claude <noreply@anthropic.com>
Rebuild full writable checkout state from the canonical session before PUT updates, preserving existing item input, buyer details, payment selection, and supported extension fields while applying customer-supplied changes. Re-read the persisted checkout after updating so the response matches checkout get and detects payment selections the backend silently substitutes.\n\nRemove unsupported --clear-items, surface buyer details in checkout responses, add complete-payment visibility guidance, and document the refined update behavior.\n\nCo-Authored-By: Claude <noreply@anthropic.com>
Retrieve the canonical checkout before completion, disclose its required agreements, and send each distinct required agreement key with an RFC 3339 acceptance timestamp when --agree is supplied. Keep optional agreements out of the payload and fail locally with agreement details when acknowledgement is absent. Refresh the typed Shopping client for consent and required-agreement fields, move Shopping mutation idempotency to the standard header, and render complete checkout state after create, get, and update. Co-Authored-By: Claude <noreply@anthropic.com>
Preserve the Shopping client and generated catalog exclusion while adopting main's Hosting, configuration, and API-catalog updates. Validate the merged workspace and a Test Shopping purchase journey. Co-Authored-By: Claude <noreply@anthropic.com>
Resolve completed checkout product IDs through the catalog before purchase, then suggest the relevant Hosting and Email setup guides. Keep category-to-action mappings centralized and document how to extend them for future Shopping products. Co-Authored-By: Claude <noreply@anthropic.com>
Prune nonessential documentation and verbose response examples from the normalized Shopping OpenAPI while retaining string-array examples. Apply the transformation during catalog regeneration and verify the regenerated typed client through a Test purchase journey. Co-Authored-By: Claude <noreply@anthropic.com>
Objective
Expose a beta-gated Shopping customer journey through
gddy: discover products, create and review a checkout session, accept the checkout's required agreements, place an order, and retrieve the completed order.Customer workflow
shopping catalog categories,search,lookup, andgetshopping checkout create,get,update, andcompleteshopping order getShopping is registered behind
Stage::Betaat the top-level module, so it remains hidden at the default GA stage. Promoting it later is a one-line removal of that module feature flag.What changed
Catalog and checkout experience
catalog categories --refresh.--show-all-payment-instruments), buyer details, totals, links, and required agreements.Agreement consent
required_agreementsresponse field, including title, key, URL, and required state.checkout completerequires--agree; without it, the CLI names each required agreement and provides its URL.--agree, the CLI sends every distinct required agreement key inconsent.agreement_types, with a current UTC RFC 3339consent.agreed_attimestamp.--payment-instrumentis optional when a method is already selected.Generated client and request safety
Idempotency-KeyHTTP header support for create, update, and complete. The obsolete completion-body idempotency field was removed after Test verification.--billing-addressinput.Documentation and tests
Test deployment verification
The Order Management MCP Test deployment completed successfully and now returns required agreements.
Using the Test environment with a scoped PAT, verified the complete Hosting customer journey:
universal_terms_and_conditionsreturned inrequired_agreements.--agreeis rejected locally before purchase.--agree, which sent consent using the displayed required agreement key.The successful Test order was
2211357178. Full, unredacted commands and command output are retained locally under ignoredstash/shopping-consent-e2e-20260915/README.md.Validation
Executed from
rust/:All checks passed.
cargo test --workspacepassed with 874 tests and no failures. Cargo audit found no vulnerabilities; it reports two existing explicitly allowed dependency warnings.🤖 Generated with Claude Code